import { get } from 'lodash-es';
import { createIcon, getLngLat } from '../CMap/mapUtils.js';

export function createMarker(data) {
  /*
   * { title:"", icon:"", longitude:"", latitude:""  }
   * */
  const opt = {
    enableClicking: true,
    enableMassClear: true,
    enableDragging: false,
    rotation: 0,
  };
  data = Object.assign(opt, data, {
    icon: createIcon(data.icon),
    title: data.title || data.name || '',
  });
  const point = new BMap.Point(...(getLngLat(data) || []));
  const marker = new BMap.Marker(point, data);
  marker.extraData = data;
  Object.keys(data).forEach((key) => {
    if (/^on[A-Z]\w+/.test(key) && typeof data[key] === 'function') {
      const event = key.replace(/^on([A-Z])/, ($0, $1) => $1.toLowerCase());
      marker.addEventListener(event, data[key]);
    }
  });
  return marker;
}

export function updateMarker(marker, data) {
  const extraData = marker.extraData;
  if (data.icon !== extraData.icon) {
    marker.setIcon(createIcon(data.icon));
  }
  if (data.title !== extraData.title) {
    marker.setTitle(data.title);
  }
  marker.setPosition(getLngLat(data));
  marker.extraData = Object.assign(extraData, data);
}

export function showMarker(map, marker) {
  if (!marker || !(marker instanceof BMap.Marker)) {
    return;
  }
  if (!map || !(map instanceof BMap.Map)) {
    throw new Error('map as first param is required !');
  }
  if (!marker.getMap()) {
    map.addOverlay(marker);
  }
  marker.show();
}

export function hideMarker(marker) {
  if (!marker || !(marker instanceof BMap.Marker)) {
    return;
  }
  marker.hide();
}

export default class BaiduMapMarkers {
  constructor(map) {
    // require('@/components/BMap/TextIconOverlay');
    // require('@/components/BMap/BMapLibMarkerClusterer');
    // console.log(BMapLib);
    this.map = map;
    this.markers = {};
    this.layer = new BMapLib.MarkerClusterer(map, {});
  }
  getUniqueKey(item) {
    const key = get(item, 'id');
    if (!key) throw new Error('unique key is required !');
    return key;
  }
  getCondition(key) {
    const marker = this.markers[key];
    return marker ? { data: marker.extraData, marker: marker } : null;
  }
  getMarker(predicate) {
    if (typeof predicate !== 'function') {
      return Object.keys(this.markers).map((key) => this.markers[key]);
    }
    return Object.keys(this.markers).reduce((res, key) => {
      return predicate(this.getCondition(key)) ? res.concat([this.markers[key]]) : res;
    }, []);
  }
  getData(predicate) {
    return this.getMarker(predicate).map((item) => item.extraData);
  }
  isVisible({ data, marker }) {
    /* 实例中自定义 isVisible 方法可实现新增加的 marker 会根据 isVisible 的返回值决定是否显示 */
    return data && marker;
  }
  update(list) {
    if (!list || !list.length) return;
    let key, marker;
    list.forEach((item) => {
      key = this.getUniqueKey(item);
      marker = this.markers[key];
      if (marker) {
        updateMarker(marker, item);
      } else {
        marker = createMarker(item);
        this.markers[key] = marker;
        this.layer.addMarker(marker);
      }
    });
  }
  remove(predicate) {
    if (typeof predicate !== 'function') {
      predicate = () => true;
    }
    Object.keys(this.markers).forEach((key) => {
      if (predicate(this.getCondition(key))) {
        this.map.removeOverlay(this.markers[key]);
        delete this.markers[key];
      }
    });
  }
  show(predicate) {
    if (typeof predicate !== 'function') {
      predicate = this.isVisible;
    }
    Object.keys(this.markers).forEach((key) => {
      if (predicate(this.getCondition(key))) {
        showMarker(this.map, this.markers[key]);
      }
    });
  }
  toggle(predicate) {
    if (typeof predicate !== 'function') {
      predicate = this.isVisible;
    }
    Object.keys(this.markers).forEach((key) => {
      !predicate(this.getCondition(key)) ? hideMarker(this.markers[key]) : showMarker(this.map, this.markers[key]);
    });
  }
  destroy() {
    Object.keys(this.markers).forEach((key) => {
      this.map.removeOverlay(this.markers[key]);
    });
    this.map = null;
    this.markers = null;
  }
}
